Hello!大家好!前幾天突然看到鐵人賽在十月開始,實在來的太快,讓小弟我感到非常錯愕XD,去年因為害怕所以沒有參加,但那時候也立志了今年要參加的決心!所以之後會好好準備那三十篇或以上的文章,Vue.js的更新可能就不會那麼頻繁,這一次真的真的真的不是偷懶的藉口XD,鐵人賽開幕時,再請各位大大多多指教了!
好的,題外話再分隔線以上結束,那來談談所謂的組件吧!組件在Vue中是個很重要的應用,所以我會分成幾個篇幅來說明,避免一篇文章中的資訊量太大讓人看了就想放棄XD。
組件類似於創建一個HTML
的標籤,而該標籤的內容是在Vue
的component
屬性中設定的,在設定的同時我們他一個名稱,該名稱能夠在所有透過new Vue
建立的實體中使用,聽起來很抽象嗎?讓我們來看看以下例子:
HTML
<div id="ex1">
<!--直接下在component中設定的名稱為標籤-->
<input-name></input-name>
</div>
JavaScript
//透過Vue的component創建一個組件,第一個值為該組件的名稱,第二個值為組件內容的物件
Vue.component('inputName',{
data:()=>{
return {
inputType:'姓名',
place:'Name',
}
},
template:`<div>
<span>請輸入{{inputType}}:</span>
<input :placeholder="place" />
</div>`
})
//創建一個Vue的實體
let ex1 = new Vue({
el:'#ex1',
})
值得注意的有幾個地方:
第一個是我在Vue.component('inputName',{...})
設定的組件名稱和我在HTML
標籤中的名稱不同,那是因為DOM
的標籤只支援短橫線命名法
,但是Vue.js並不會阻止你在創建組建的時候一定要用短橫線命名法
,所以即使用駝峰命名法
創建新組件,在HTML
中還是要把他轉成短橫線命名法
才行。
第二個是Vue.component
和其他Vue物件一樣,都擁有data
、methods
、computed
和watch
,但是他並不是對某個DOM
建立實體,所以他不會有el
。此外,data
的值必須要是方法的回傳值;而回傳的是一個物件,這樣會讓每次創建一個組件實體的時候,都會重新new
一個新的data
,讓每次使用的相同組件都擁有自己獨立的data
,這個部份可以參考下方的官方例子:
HTML
<div id="demoCounter">
<!--一個組件可多次使用-->
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
JavaScript
Vue.component('button-counter', {
data:function () {
return {
count: 0
}
},
template:`<div>
<button @click="count++">請點我</button>
<span>目前點了{{count}}下</span>
</div>`
})
let counter = new Vue({
el:'#demoCounter'
})
上圖中重複使用了三次同一個組件,但是他們的count
卻不是共用,而是獨立的。
第三個是上方的例子都是在全域中使用Vue.component('inputName',{...})
建立組件,在全域中建立組件的話,不管是在頁面中任一個被new Vue
過的DOM
中都可以使用,但是組件並不是只能在全域中建立而已,他也可以針對某一個Vue物件建立,而用這種方式的話,該組件就只能夠在該DOM
使用而已,可以看一下下方的例子:
HTML
<!--在被new Vue的DOM使用該組件-->
<div id="ex1">
<input-name></input-name>
</div>
<!--inputName組件並不在ex2的new Vue物件中-->
<div id="ex2">
<input-name></input-name>
</div>
JavaScript
//建立一個組件的物件
let componentsInputName = {
data:()=>{
return {
inputType:'姓名',
place:'name',
}
},
template:`<div>
<span>請輸入{{inputType}}:</span>
<input :placeholder="place" />
</div>`
}
let ex1 = new Vue({
el:'#ex1',
/*在new Vue中也可以使用components屬性,
key為組件名稱,值為組件內容*/
components:{
inputName:componentsInputName
}
})
let ex2 = new Vue({
el:'#ex2',
})
在某個Vue
物件中創建組件時,就只有對應該物件的DOM
中可以使用組件而已,所以上方HTML
中第二個div``ex2
內雖然也有input-name
,但設定的組件並不會出現,因為他只能在id="ex1"
的DOM
中使用。
再來提的是如果要在組件內使用另一個組件該怎麼做,其實很簡單,只需要在該組件的物件中增加一個components
屬性,並設定該子組件的資料即可,讓我們看看以下的例子:
HTML
<div id="ex1">
<red-div></red-div>
</div>
JavaScript
//建立一個組件的物件,一個藍色的div
let componentsBlueDiv = {
data:()=>{
return {
blueStyle:{
height:'50px',
width:'100px',
backgroundColor:'blue',
},
}
},
template:`<div :style="blueStyle"></div>`
}
//建立一個組件的物件,是紅色的div
let componentsRedDiv = {
/*在該組件中用components,
指定一個組件名稱blueDiv為上面建立的componentsBlueDiv*/
components:{
blueDiv:componentsBlueDiv,
},
data:()=>{
return {
redStyle:{
height:'100px',
width:'200px',
backgroundColor:'red',
},
}
},
//在template中直接使用上述設定的組件
template:`<div :style="redStyle"><blue-div></blue-div></div>`,
}
let ex1 = new Vue({
el:'#ex1',
components:{
//所以這時候的redDiv會有componentsBlueDiv和componentsRedDiv兩個div
redDiv:componentsRedDiv,
},
})
像上方程式那樣設定就能建立一個有父子關係的組件,但是他並不能像以下使用(小弟我一開始這樣寫,卡到一個天荒地老,拯救我的文章是這篇):
<div id="ex1">
<red-div><blue-div></blue-div></red-div>
</div>
題外話是看到畫面突然發現有點像國旗XD
關於建立組件最後要提的一點是,當組件中不只有一個DOM
時,必須包在一個div
或任何父元素內,因為每個組件都只能擁有一個根元素,這部分在一開始也卡了很久
Props
傳遞數據好的,出現的東西越來越多,這又是做什麼用的呢?先讓我們來看看以下程式碼:
HTML
<div id="ex1">
<input-name></input-name>
<input-nickname></input-nickname>
</div>
JavaScript
Vue.component('inputName',{
data:()=>{
return {
inputType:'姓名',
place:'Name',
}
},
template:`<div>
<span>請輸入{{inputType}}:</span>
<input :placeholder="place" />
</div>`
})
Vue.component('inputNickname',{
data:()=>{
return {
inputType:'暱稱',
place:'Nickname',
}
},
template:`<div>
<span>請輸入{{inputType}}:</span>
<input :placeholder="place" />
</div>`
})
let ex1 = new Vue({
el:'#ex1',
})
雖然只是兩個組件,但是他們明明就差不多卻因為某些地方不同,就要再另外新建立一個組件,看起來是不是很受不了?這時候我們就需要Props
這個屬性來協助我們處理這個問題,先看一下加入Props
後的程式碼:
HTML
<div id="ex1">
<!--在使用組件時可依屬性傳遞參數的值-->
<input-data title="姓名" place="Name"></input-data>
<input-data title="暱稱" place="Nicename"></input-data>
</div>
JavaScript
Vue.component('input-data',{
//使用props接收參數的值,陣列中的值是key對應屬性傳過來的資料,順序沒關係
props:['title','place'],
//可在組件中直接使用props內的key,會帶入組件使用時的屬性值
template:`<div>
<span>請輸入{{title}}:</span>
<input :placeholder="place" />
</div>`
})
let ex1 = new Vue({
el:'#ex1',
})
最後得到的結果會和上方一樣,但是程式碼的部分明顯的差很多!個人私心認為這個屬性還滿酷的,主要是在組件的props
屬性內先設定key值,之後在HTML
上使用的時候依照陣列中的key傳入值。
但是Don't repeat yourself
,重複的事情我們就不做了,所以既然長的差不多,就用迴圈吧!最後加上迴圈v-for
的樣子:
HTML
<div id="ex1">
<input-data v-for="type in types" :title="type.title" :place="type.place"></input-data>
</div>
JavaScript
Vue.component('input-data',{
props:['title','place'],
template:`<div>
<span>請輸入{{title}}:</span>
<input :placeholder="place" />
</div>`
})
let ex1 = new Vue({
el:'#ex1',
data:{
types:[
{title:'姓名',place:'Name'},
{title:'暱稱',place:'Nicename'}
]
}
})
但是這麼做的話,當一個組件的key越來越多,使用組件的時候就必須設定更多的屬性和值,這個時候我們可以直接對某個key傳入整個物件,讓我們再重構一下程式:
HTML
<div id="ex1">
<input-data v-for="type in types" :data="type"></input-data>
</div>
JavaScript
Vue.component('input-data',{
//用data接收陣列內的每一個物件內容
props:['data'],
//傳進來的物件會跑進data中,所以data也會是物件
template:`<div>
<span>請輸入{{data.title}}:</span>
<input :placeholder="data.place" />
</div>`
})
let ex1 = new Vue({
el:'#ex1',
data:{
types:[
{title:'姓名',place:'Name'},
{title:'暱稱',place:'Nicename'}
]
}
})
這幾個例子中,使用props
簡略了JavaScript
的部分,接著用v-for
和傳入data
內的整個物件再一次簡略了HTML
的部分,而實務上每個方式都應該會有適合使用的地方,所以學會運用還是最重要的!
下一篇會繼續說明有關組件的事件使用和v-model
雙向綁定,希望可以把組件基礎的部分補完,之後會有組件的進階篇,那時候一定會更燒腦,不過文章中會盡量把每個講到的東西都舉例出來,讓大家不會和我一樣因為不熟悉而卡關XD,但是說不定還是會有漏掉的地方,只能請大大們留言指導我一下了,謝謝!
那分隔線下面的地方,也感謝各位大大觀看這篇文章,如果以上有理解錯誤或是解釋不清楚的地方,再麻煩留言告訴我,我會盡快修正文章內容的,謝謝大家
感謝分享
補充 new Vue() 是 Vue 2 語法,
Vue 3 用 Vue.createApp() 取代 new Vue()
https://book.vue.tw/appendix/migration.html#%E5%85%83%E4%BB%B6%E5%AF%A6%E9%AB%94%E5%BB%BA%E7%AB%8B
Vue 2 support will end on Dec 31, 2023. Learn more about Vue 2 Extended LTS.
The Benefits of the New Vue 3 App Initialization Code